#!/usr/bin/env python3
import socket, sys, argparse
from scapy.all import IP, UDP, Ether, Packet, bind_layers, get_if_hwaddr, get_if_list, sendp
from scapy.fields import BitField

def get_if():
    for i in get_if_list():
        if "eth0" in i:
            return i
    print("Cannot find eth0 interface")
    sys.exit(1)

class SourceRoute(Packet):
   fields_desc = [ BitField("bos", 0, 1),
                   BitField("port", 0, 15)]
bind_layers(Ether, SourceRoute, type=0x1234)
bind_layers(SourceRoute, SourceRoute, bos=0)
bind_layers(SourceRoute, IP, bos=1)

def main():
    parser = argparse.ArgumentParser(description="Dual-mode sender: IPv4 or Source Routing")
    parser.add_argument("dst", help="Destination IP (e.g., 10.0.2.2)")
    parser.add_argument("--mode", choices=["ip","sr"], default="sr")
    parser.add_argument("--ports", default="", help='Space/comma separated SR ports, e.g. "2 3 1"')
    args = parser.parse_args()

    addr = socket.gethostbyname(args.dst)
    iface = get_if()
    print(f"sending on interface {iface} to {addr} (mode={args.mode})")

    if args.mode == "ip":
        pkt = Ether(src=get_if_hwaddr(iface), dst='ff:ff:ff:ff:ff:ff')/IP(dst=addr)/UDP(dport=4321, sport=1234)
        pkt.show2()
        sendp(pkt, iface=iface, verbose=False)
        return

    ports = args.ports.strip().replace(",", " ").split()
    if not ports or ports == ['']:
        print('No --ports provided for --mode sr, example: --ports "2 3 2 1"')
        sys.exit(1)

    pkt = Ether(src=get_if_hwaddr(iface), dst='ff:ff:ff:ff:ff:ff')
    i = 0
    for p in ports:
        pkt = pkt / SourceRoute(bos=0, port=int(p))
        i += 1
    pkt.getlayer(SourceRoute, i).bos = 1
    pkt = pkt / IP(dst=addr) / UDP(dport=4321, sport=1234)
    pkt.show2()
    sendp(pkt, iface=iface, verbose=False)

if __name__ == '__main__':
    main()